package guet.imagan.progbuilder;

import guet.imagan.util.ListUtil;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 代表一个可执行文件对象
 */
public abstract class ExecuteFile extends File {
	/**
	 * 进程构建器
	 */
	private ProcessBuilder processBuilder;
	/**
	 * 带独立窗口运行可执行文件对象的命令行命令
	 */
	private List<String> cmdLineWithWindow;
	/**
	 * 以后台方式运行可执行文件对象的命令行命令
	 */
	private List<String> cmdLineWithoutWindow;
	/**
	 * 程序运行的超时时间，超过此时间，程序将自动关闭，单位：秒
	 */
	private long timeout;

	/**
	 * 创建一个可执行文件对象
	 *
	 * @param filename 可执行文件路径
	 */
	public ExecuteFile(String filename) {
		super(filename);
		processBuilder = new ProcessBuilder();
		cmdLineWithWindow = new ArrayList<>();
		cmdLineWithoutWindow = new ArrayList<>();
		timeout = 10;

	}


	/**
	 * 以独立窗口的方式运行程序
	 *
	 * @param args 程序运行时所附加的命令行参数
	 */
	public void executeWithWindow(String... args) throws ExecuteFileException {
		List<String> cmd = processBuilder.command();
		cmd.clear();
		cmd.addAll(cmdLineWithWindow);
		processBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE);
		processBuilder.redirectError(ProcessBuilder.Redirect.PIPE);
		processBuilder.redirectInput(ProcessBuilder.Redirect.PIPE);
		updateCommandLine(cmd, args);
		Process p;
		try {
			p = processBuilder.start();
			p.waitFor(timeout, TimeUnit.SECONDS);
		} catch (IOException | InterruptedException e) {
			throw new ExecuteFileException(e.getMessage());
		}
	}

	/**
	 * 后台方式运行程序
	 *
	 * @param inputFile 输入重定向文件
	 * @param args      额外的命令行参数
	 * @return 重定向输出文件
	 */
	public TextFile executeWithoutWindow(TextFile inputFile, String... args) throws ExecuteFileException {
		processBuilder.redirectInput(inputFile);
		TextFile outputFile = new TextFile(getParent() + File.separator + "output.txt");
		processBuilder.redirectOutput(outputFile);
		List<String> cmd = processBuilder.command();
		cmd.clear();
		cmd.addAll(cmdLineWithoutWindow);
		updateCommandLine(cmd, args);
		Process p;
		try {
			p = processBuilder.start();
			p.waitFor(timeout, TimeUnit.SECONDS);
		} catch (IOException | InterruptedException e) {
			throw new ExecuteFileException(e.getMessage());
		}
		return outputFile;
	}

	/**
	 * 将占位符({filename})用实际文件路径取代，更新命令行对象
	 *
	 * @param cmd  命令行
	 * @param args 额外参数
	 */
	private void updateCommandLine(List<String> cmd, String... args) {
		for (int k = 0; k < cmd.size(); k++) {
			String s = cmd.get(k);
			ListUtil.replaceFirst(cmd, "{filename}",getAbsolutePath());

		}
		cmd.addAll(Arrays.asList(args));

	}

	/**
	 * 返回超时时间
	 *
	 * @return 超时时间，单位为秒
	 */
	public long getTimeout() {
		return timeout;
	}

	/**
	 * 设置程序运行的超时时间，单位：秒
	 *
	 * @param n n秒
	 */
	public void setTimeout(long n) {
		timeout = n;
	}


	public ProcessBuilder getProcessBuilder() {
		return processBuilder;
	}

	public List<String> getCmdLineWithWindow() {
		return cmdLineWithWindow;
	}

	/**
	 * 设置在独立窗口运行程序的命令行命令
	 * @param cmdLineWithWindow
	 */
	public void setCmdLineWithWindow(List<String> cmdLineWithWindow) {
		this.cmdLineWithWindow.clear();
		this.cmdLineWithWindow.addAll(cmdLineWithWindow);
	}

	public List<String> getCmdLineWithoutWindow() {
		return cmdLineWithoutWindow;
	}

	/**
	 * 设置在后台窗口执行程序的命令行命令
	 * @param cmdLineWithoutWindow
	 */
	public void setCmdLineWithoutWindow(List<String> cmdLineWithoutWindow) {
		this.cmdLineWithoutWindow.clear();
		this.cmdLineWithoutWindow.addAll(cmdLineWithoutWindow);
	}
}
